package client

import (
	"database/sql"
	"fmt"
	"sync"
	"time"

	"github.com/olivere/elastic"

	redis "github.com/go-redis/redis/v7"
	_ "github.com/lib/pq"
	log "github.com/sirupsen/logrus"
	"qabx.net/common/config"
	v1 "qabx.net/common/types/v1"
)

func InitPGConnection() *sql.DB {
	var err error
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		config.Cfg.PostgreSQL.Host, config.Cfg.PostgreSQL.Port, config.Cfg.PostgreSQL.Username, config.Cfg.PostgreSQL.Password, config.Cfg.PostgreSQL.DBName)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		log.Errorf("init postgresql failed: %v", err)
		return nil
	}

	err = db.Ping()
	if err != nil {
		log.Errorf("init postgresql failed: %v", err)
		return nil
	}
	log.Info("Successfully connect to postgresql db")
	return db
}

func InitElasticsearchConnection() *elastic.Client {
	elasticsearchClient := newElasticSearchClient(config.Cfg.ElasticSearch.Url, "", "")
	if elasticsearchClient == nil {
		log.Error("init elasticsearch connection failed")
		return nil
	}

	return elasticsearchClient
}

func InitRedisConnection() *v1.RedisConnection {
	redisClient := newConnectionWithParams(config.Cfg.Redis.Url, 10, 0, "")
	if redisClient == nil {
		log.Errorf("init redis connection failed")
		return nil
	}

	return redisClient
}

func newElasticSearchClient(Url string, esusername string, espassword string) *elastic.Client {
	client, err := elastic.NewClient(
		elastic.SetSniff(false),
		elastic.SetURL(Url),
		elastic.SetBasicAuth(esusername, espassword))
	if err != nil {
		log.Errorf("failed to create elasticsearch client: %v", err)
		return nil
	}

	return client
}

func newConnectionWithParams(url string, poolSize int, db int, password string) *v1.RedisConnection {
	redisClient := &v1.RedisConnection{}
	redisClient.Client = redis.NewClient(&redis.Options{
		Addr:        url,
		IdleTimeout: time.Second * 120,
		Password:    password,
		DB:          db,
		PoolSize:    poolSize,
		PoolTimeout: time.Second * 120,
	})

	if redisClient.Client == nil {
		return nil
	}
	redisClient.Mutex = &sync.Mutex{}

	return redisClient
}
